/* eslint-disable no-debugger */
/* eslint-disable no-unused-vars */
import CreateKnowledgeGraph from './CreateKnowledgeGraph'
import { defsDomData } from '../data/data'

// 默认模式
export default class DefaultMode extends CreateKnowledgeGraph{
  constructor(options) {
    super(options)
    this.lines = null
    this.lineAnimation = null
    this.nodeGroups = null
    this.circles = null
    this.texts = null
  }

  // 默认模式初始化
  DefaultModeInit(){
    console.log(this.data,'默认模式初始化')

    // 初始化defs
    this.defsInit()
    // 初始化数据
    this.dataInit()
    // 初始化元素
    this.domInit()
    // 渲染动态变化的值
    this.reRender()
    // 初始化拖拽
    this.dragInit()
    // 初始化事件
    this.emitInit()
    // 更新位置
    this.updateAllPosition()
    // 更新节点旋转角度
    this.updateNodeRotate()
    // 移动元素到屏幕中央
    this.setCenter()
    // 初始化隐藏状态
    this.changeHideType()
  }

  // 初始化数据
  dataInit(){
    // 处理节点数据

    // 遍历一级节点
    const levelOneNodes = this.data.nodeList.filter(node => node.level === 1)
    // 计算圆形轨迹
    this.calculateCircular(levelOneNodes,370,0,0)

    // 遍历二级节点
    const result = this.data.lineList.reduce((acc, cur) => {
      const source = cur.source
      const target = cur.target
      if (this.data.nodeList.find(item=>item.id==cur.source).level==1) {
        if (!acc[source]) {
          acc[source] = []
        }
        acc[source].push(this.data.nodeList.find((item)=>item.id==target))
      }
      return acc
    }, {})
    for (const key in result) {
      if (Object.prototype.hasOwnProperty.call(result, key)) {
        const parentNode = this.data.nodeList.find(item=>(item.id==key && item.level==1))
        const element = result[key]
        // 计算圆形轨迹
        this.calculateCircular(element,130,parentNode.x,parentNode.y)
      }
    }

    // 处理线数据
    this.data.lineList.forEach((item)=>{
      const {source,target} = item
      const {x:x1,y:y1} = this.data.nodeList.find(item=>item.id==source)
      const {x:x2,y:y2} = this.data.nodeList.find(item=>item.id==target)
      item.x1 = x1
      item.y1 = y1
      item.x2 = x2
      item.y2 = y2
    })
  }

  // 初始化元素
  domInit(){
    // 创建线
    this.lines = this.graphInfo.collectionZoom
      .selectAll('.d_line')
      .data(this.data.lineList)
      .enter()
      .append('path')
      .attr('stroke-width','1')
      .attr('class',(d) => `d_groupsLevel_${this.data.nodeList.find(item=>item.id==d.source).level}`)
      .attr('id',(d)=>`d_line_${d.source}_${d.target}`)
      .attr('marker-end','url(#d_marker_arrow)')
      .attr('fill','none')

    // 创建根节点箭头动画
    this.lineAnimation = this.graphInfo.collectionZoom
      .selectAll('.d_line_animation')
      .data(this.data.lineList)
      .join('circle')
      .attr('class',(d) => `d_line_animation d_groupsLevel_${this.data.nodeList.find(item=>item.id==d.source).level}`)
      .attr('r', 7)
      .attr('fill','none')

    // 添加根节点箭头动画的条件判断
    this.lineAnimation.filter((d) => {
      return this.data.nodeList.find(item => item.id === d.source).level === 0
    }).attr('fill', 'url(#d_arrow_animation)')
      .append('animateMotion')
      .attr('dur', '2s')
      .attr('repeatCount', 'indefinite')
      .attr('rotate', 'auto')
      .attr('keyPoints', '0;0.95')
      .attr('keyTimes', '0;1')
      .append('mpath')
      .attr('xlink:href', (d)=>{
        return `#d_line_${d.source}_${d.target}`
      })

    // 创建一级节点虚线动画
    this.lines.filter((d) => {
      return this.data.nodeList.find(item => item.id === d.source).level === 1
    }).attr('stroke-dasharray','5')
      .append('animate')
      .attr('attributeName','stroke-dashoffset')
      .attr('attributeType','XML')
      .attr('repeatCount','indefinite')
      .attr('from','0')
      .attr('to','-100')
      .attr('dur','5')

    // 创建组
    this.nodeGroups = this.graphInfo.collectionZoom
      .selectAll('d_group')
      .data(this.data.nodeList)
      .enter()
      .append('g')
      .attr('class','d_group')
      .attr('id',(d)=>`d_node_${d.id}`)
      .attr('class',(d)=> `d_groupsLevel_${d.level}`)

    // 创建节点，上根节点样式
    this.circles = this.nodeGroups
      .filter((d) => d.level === 0)
      .append('circle')
      .attr('r', (d) => this.config.nodeSize[+d.level].r)
      .attr('class','d_circle')
      .attr('stroke-width','1')


    // 定义大小比例尺
    const sizeScaleList = []
    this.data.nodeList.forEach(item=>{
      if (item.level==1) {
        sizeScaleList.push(this.data.lineList.filter(lineItem=>lineItem.source==item.id).length)
      }
    })
    const sizeScale = this.d3.scaleSqrt()
      .domain([1, this.d3.max(sizeScaleList)])
      .range([10, 55])

    // 上一级节点样式
    this.nodeGroups
      .filter((d) => d.level === 1)
      .append('circle')
      .attr('r', (d) => {
        const _sum = this.data.lineList.filter(item=>item.source==d.id).length
        return sizeScale(_sum)
      })
      .attr('class','d_circle')
      .attr('stroke-width','3')

    // 上二级节点样式
    this.nodeGroups
      .filter((d) => d.level === 2)
      .append('polygon')
      .attr('points', '40,-10 70,80 -5,20 85,20 10,80')
      .attr('transform', () => 'translate(-40,-40)')
      .attr('class','d_circle')

    // 创建文本
    this.texts = this.nodeGroups
      .append('text')
      .attr('class','d_text')
      .attr('x', 0)
      .attr('y', -3)
      .attr('dy', 10)
      .attr('font-size',(d) => {
        return this.config.nodeSize[+d.level].fontSize
      })
      .attr('text-anchor', 'middle')
      .text((d) => d.name)
  }

  // 初始化defs
  defsInit() {
    this.graphInfo.collectionSvg.select('defs').remove()
    this.graphInfo.collectionSvg.append('defs').html(defsDomData.apply(this))
  }

  // 初始化拖拽
  dragInit(){
    // 绑定拖拽
    this.nodeGroups.call(this.d3.drag()
      .on('drag', (event, d) => {

        // 改变节点数据
        d.x = event.x
        d.y = event.y

        // 改变线的数据
        this.data.lineList.forEach(item => {
          const {source,target} = item
          if (source == d.id) {
            item.x1 = event.x
            item.y1 = event.y
          }else if(target == d.id){
            item.x2 = event.x
            item.y2 = event.y
          }
        })

        // 更新位置
        this.updateAllPosition()

      })
      .on('end', () => {
        console.log('Drag ended')
        // 更新节点旋转角度
        this.updateNodeRotate()
      }))
  }

  // 初始化事件
  emitInit(){
    this.texts.on('click',this.config.handleClick)
  }

  // 更新位置
  updateAllPosition(){
    // 更新节点位置
    this.nodeGroups.attr('transform', (d) => 'translate(' + d.x + ',' + d.y + ')')
    // 更新线位置
    this.lines.attr('d',(d) => this.updateLine(d))
  }

  // 更新节点旋转角度
  updateNodeRotate(){
    this.lines.each((d) => {
      // 获取角度
      const deg = (((Math.atan2(d.y2 - d.y1, d.x2 - d.x1) * 180) / Math.PI + 360) % 360 ) + 90
      // 更改朝向
      this.d3
        .select(`#d_node_${d.target} text`)
        .attr(
          'transform',
          `rotate(${deg})`
        )
    })
  }

  // 重新渲染
  reRender(){
    console.log('重新渲染')
    this.circles
      .attr('stroke', (d) => {
        let color = ''
        if (d.level==0) {
          color = this.config.theme=='dark'?'#f5f5dc':'#fff'
        } else if (d.level==1){
          color = this.config.theme=='dark'?'#f5f5dc':'#8695A8'
        }
        return color
      })

    // 重新渲染-节点
    this.nodeGroups
      .attr('fill', (d) => {
        let color = ''
        if (d.level==0) {
          color = 'url(#gradientBallLevel0)'
        } else if (d.level==1){
          color = 'url(#gradientBallLevel1)'
          // // 颜色比例尺
          // const data = [1, 2, 3,4, 5, 6, 7, 8, 9,10]
          // const _sum = this.data.lineList.filter(item=>item.source==d.id).length
          // const colorScale = this.d3.scaleSequential(this.d3.interpolateBlues)
          //   .domain([1, this.d3.max(data)])
          // // 颜色赋值
          // color = this.config.theme=='dark'? '#fff':colorScale(_sum)
        } else if (d.level==2){
          color = this.config.theme=='dark'?'#f5f5dc':'#FFD467'
        }
        return color
      })

    // 重新渲染-文本
    this.texts
      .attr('fill',()=> this.config.theme=='dark'?'#000':'#fff')

    // 重新渲染-线
    this.lines.data(this.data.lineList)
      .attr('stroke',this.config.theme=='dark'?'#fff':'#000')

  }

  // 切换主题
  changeThemeInside(theme){
    this.changeTheme(theme)
    this.defsInit()
    this.reRender()
  }

  // 初始化按钮
  initialize(data){
    this.graphInfo.collectionZoom.selectAll('*').remove()
    this.data = JSON.parse(JSON.stringify(data))
    this.DefaultModeInit()
  }

  // 更新线条位置
  updateLine(d) {
    const _sourceLevel = this.data.nodeList.find(item=>item.id == d.source).level
    const _targetLevel = this.data.nodeList.find(item=>item.id == d.target).level

    // 起点终点圆的半径
    const sourceR = this.config.nodeSize[_sourceLevel].r+10
    const targetR = this.config.nodeSize[_targetLevel].r+10

    // 获取角度
    const deg = (((Math.atan2(d.y2 - d.y1, d.x2 - d.x1) * 180) / Math.PI + 360) % 360 ) + 90

    // 获取弧度
    const sourceOffset = getTriangleLength(sourceR, deg)
    const targetOffset = getTriangleLength(targetR, deg)

    // 线段位置
    const x1 = d.x1 + sourceOffset.x
    const y1 = d.y1 - sourceOffset.y
    const x2 = d.x2 - targetOffset.x
    const y2 = d.y2 + targetOffset.y
    const distance = calculateDistance(x1,y1,x2,y2)
    const {x,y} = calculateIsoscelesTriangleVertex({x:x1, y:y1},{x:x2,y:y2}, distance/3)

    let result = `M ${x1} ${y1} Q ${x} ${y} ${x2} ${y2}`

    if (_sourceLevel==1) {
      result = `M ${x1} ${y1} L${x2} ${y2}`
    }

    return result
  }

  // 保存
  handleSave(){
    this.save(()=>{
      const resultDataJSON = JSON.stringify(this.data)
      localStorage.setItem('resultDataJSON', resultDataJSON)
    })
  }

}

// 获取弧度函数
function getTriangleLength(l, deg) {
  const radian = (deg * Math.PI) / 180
  return {
    x: l * Math.sin(radian),
    y: l * Math.cos(radian)
  }
}

// 获取两点之间的距离
function calculateDistance(x1, y1, x2, y2) {
  const dx = x2 - x1
  const dy = y2 - y1
  return Math.sqrt(dx * dx + dy * dy)
}

// 计算弧线控制点位置
function calculateIsoscelesTriangleVertex(A, B, distance) {
  // 计算中点 M
  const Mx = (A.x + B.x) / 2
  const My = (A.y + B.y) / 2

  // 计算线段 AB 的长度 d
  const d = Math.sqrt((B.x - A.x) ** 2 + (B.y - A.y) ** 2)

  // 计算单位向量 u
  const ux = (B.x - A.x) / d
  const uy = (B.y - A.y) / d

  // 计算点 C 的坐标
  const Cx = Mx + distance * (-uy) / Math.sqrt(1 + ux ** 2 + uy ** 2)
  const Cy = My + distance * ux / Math.sqrt(1 + ux ** 2 + uy ** 2)

  return { x: Cx, y: Cy }
}
